package com.mosai.alignpro;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.mosai.alignpro.entity.CameraParam;
import com.mosai.alignpro.entity.ImageInfo;
import com.mosai.alignpro.util.LogUtils;
import com.mosai.alignpro.util.ToastUtils;
import com.mosai.alignpro.util.Utils;
import com.mosai.alignpro.view.CameraMaskView;
import com.mosai.alignpro.view.CameraView;
import com.yalantis.ucrop.UCrop;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CameraActivity extends BaseActivity {
    public static final String TAG = CameraActivity.class.getSimpleName();

    public static final int OPEN_PICTURE = 100;
    public static final int REQUEST_CODE = 200;

    public static final String EXTRA_URI = "uri";
    public static final String EXTRA_IMAGE_TYPE = "imageType";
    public static final String EXTRA_PARAM = "param";

    private CameraView cameraView;
    private ImageView ivPicture, ivCameraPortrait;
    private boolean isLatestPhoto;
    private RadioGroup rgType;
    private RadioGroup rgSubTypeX;
    private RadioGroup rgSubTypeL;
    private CameraParam cameraParam = new CameraParam();
    private int SubTypeXCheckedId = -1;
    private int SubTypeLCheckedId = -1;

    public static void startForResult(Activity activity, int requestCode) {
        startForResult(activity, requestCode, JSON.toJSONString(new CameraParam()));
    }

    public static void startForResult(Activity activity, int requestCode, String param) {
        Intent intent = new Intent(activity, CameraActivity.class);
        intent.putExtra(EXTRA_PARAM, param);
        activity.startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);

        ivPicture = findViewById(R.id.ivPicture);
        ivCameraPortrait = findViewById(R.id.ivCameraPortrait);
        cameraView = findViewById(R.id.cameraView);
        cameraView.setOnCameraListener(uri -> {
            LogUtils.i(TAG, "onCamera"
                    + " uri: " + uri
                    + " isUiThread: " + Utils.isUiThread()
            );
            onCrop(Uri.parse(uri));
        });
        CameraMaskView cameraMaskView = findViewById(R.id.cameraMaskView);
        cameraMaskView.setOnBrightnessChangeListener(rate -> cameraView.setBrightness(rate));
        rgType = findViewById(R.id.rgType);
        rgType.setOnCheckedChangeListener((group, checkedId) -> {
            LogUtils.d(TAG, "OnCheckedChange rgType: " + checkedId);
            if (checkedId == R.id.rbX) {
                rgTypeChange(rgSubTypeX, rgSubTypeL);
            } else if (checkedId == R.id.rbL) {
                rgTypeChange(rgSubTypeL, rgSubTypeX);
            }
        });
        rgSubTypeX = findViewById(R.id.rgSubTypeX);
        rgSubTypeX.setOnCheckedChangeListener((group, checkedId) -> {
            LogUtils.d(TAG, "OnCheckedChange rgSubTypeX: " + checkedId);
            if (checkNotAvailable(group, checkedId, this.SubTypeXCheckedId)) return;
            this.SubTypeXCheckedId = checkedId;
            if (checkedId == R.id.rbX1) {
                setCameraPortrait(R.drawable.camera_x_back, 0);
            } else if (checkedId == R.id.rbX2) {
                setCameraPortrait(R.drawable.camera_x_side, 0);
            } else if (checkedId == R.id.rbX3) {
                setCameraPortrait(R.drawable.camera_x_hand, 0);
            }
        });
        rgSubTypeL = findViewById(R.id.rgSubTypeL);
        rgSubTypeL.setOnCheckedChangeListener((group, checkedId) -> {
            LogUtils.d(TAG, "OnCheckedChange rgSubTypeL: " + checkedId);
            if (checkNotAvailable(group, checkedId, this.SubTypeLCheckedId)) return;
            this.SubTypeLCheckedId = checkedId;
            if (checkedId != -1) {
                setCameraPortrait(R.drawable.camera_portrait, 0);
            }
        });

        String param = getIntent().getStringExtra(EXTRA_PARAM);
        LogUtils.d(TAG, "onCreate param: " + param);
        if (!TextUtils.isEmpty(param)) {
            cameraParam = JSON.parseObject(param, CameraParam.class);
        }
        initTypeCheck();
    }

    private void rgTypeChange(RadioGroup visibleSubType, RadioGroup goneSubType) {
        goneSubType.setVisibility(View.GONE);
        goneSubType.clearCheck();
        visibleSubType.setVisibility(View.VISIBLE);
        RadioButton child;
        for (int i = 0, count = visibleSubType.getChildCount(); i < count; i++) {
            child = (RadioButton) visibleSubType.getChildAt(i);
            if (!cameraParam.getUnavailableType().contains(Integer.parseInt(String.valueOf(child.getTag())))) {
                child.setChecked(true);
                break;
            }
        }
    }

    private boolean checkNotAvailable(RadioGroup group, int checkedId, int lastCheckedId) {
        if (checkedId == -1) return false;
        View view = group.findViewById(checkedId);
        if (view == null) return false;
        if (cameraParam.getUnavailableType().contains(Integer.parseInt(String.valueOf(view.getTag())))) {
            ToastUtils.getInstance().show(R.string.camera_hint_in_develop);
            group.check(lastCheckedId);
            return true;
        }
        return false;
    }

    private void initTypeCheck() {
        if (cameraParam.isHideTypeGroup()) {
            if (cameraParam.isNudeBack()) {
                cameraParam.setImageType(getFirstImageType(
                        ImageInfo.IMAGE_TYPE_BACK,
                        ImageInfo.IMAGE_TYPE_BACK_ANALYZE,
                        ImageInfo.IMAGE_TYPE_BACK_VR));
                initTypeCheck(rgSubTypeL, R.id.rbL, true);
            } else {
                cameraParam.setImageType(getFirstImageType(ImageInfo.IMAGE_TYPE_BACK_X,
                        ImageInfo.IMAGE_TYPE_SIDE_X,
                        ImageInfo.IMAGE_TYPE_HAND_LEFT));
                initTypeCheck(rgSubTypeX, R.id.rbX, true);
            }
            rgType.setVisibility(View.GONE);
            return;
        }
        cameraParam.setImageType(getFirstImageType(ImageInfo.IMAGE_TYPE_BACK_X,
                ImageInfo.IMAGE_TYPE_SIDE_X,
                ImageInfo.IMAGE_TYPE_HAND_LEFT,
                ImageInfo.IMAGE_TYPE_BACK,
                ImageInfo.IMAGE_TYPE_BACK_ANALYZE,
                ImageInfo.IMAGE_TYPE_BACK_VR));
        if (cameraParam.getImageType() == 0) return;
        initTypeCheck(rgSubTypeL, R.id.rbL, !initTypeCheck(rgSubTypeX, R.id.rbX, true));
    }

    public int getFirstImageType(Integer... types) {
        if (cameraParam.getImageType() == 0
                || cameraParam.getUnavailableType().contains(cameraParam.getImageType())
                || Utils.indexOf(types, cameraParam.getImageType()) == -1
        ) {
            List<Integer> typeList = new ArrayList<>(Arrays.asList(types));
            typeList.removeAll(cameraParam.getUnavailableType());
            return typeList.isEmpty() ? 0 : typeList.get(0);
        }
        return cameraParam.getImageType();
    }

    private boolean initTypeCheck(RadioGroup rgSubType, int typeResId, boolean isCheck) {
        RadioButton child;
        int type;
        boolean result = false;
        for (int i = 0; i < rgSubType.getChildCount(); i++) {
            child = (RadioButton) rgSubType.getChildAt(i);
            type = Integer.parseInt(String.valueOf(child.getTag()));
            if (cameraParam.isHideUnavailableType() && cameraParam.getUnavailableType().contains(type)) {
                child.setVisibility(View.GONE);
            }
            if (isCheck && type == cameraParam.getImageType()) {
                rgType.check(typeResId);
                child.setChecked(true);
                result = true;
            }
        }
        return result;
    }

    private void setCameraPortrait(int resId, float rotationY) {
        ivCameraPortrait.setImageResource(resId);
        ivCameraPortrait.setRotationY(rotationY);
    }

    private int getImageType() {
        if (rgType.getCheckedRadioButtonId() == R.id.rbL) {
            return getImageTypeByTag(rgSubTypeL);
        }
        return getImageTypeByTag(rgSubTypeX);
    }

    private int getImageTypeByTag(RadioGroup rgSubType) {
        View view = rgSubType.findViewById(rgSubType.getCheckedRadioButtonId());
        if (view == null) {
            return 0;
        }
        return Integer.parseInt(String.valueOf(view.getTag()));
    }

    @Override
    public void onResume() {
        super.onResume();
        cameraView.onResume();
        getLatestPhoto();
    }

    @Override
    public void onPause() {
        cameraView.onPause();
        super.onPause();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        getLatestPhoto();
        cameraView.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            onOpenPicture(null);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK || data == null) return;
        switch (requestCode) {
            case OPEN_PICTURE:
                onCrop(data.getData());
                break;
            case UCrop.REQUEST_CROP:
                onCropCallback(data);
                break;
        }
    }

    private void onCrop(Uri uri) {
        LogUtils.i(TAG, "onCrop uri: " + uri);
        if (uri == null) return;
        Uri destination = Uri.fromFile(new File(getExternalCacheDir(), System.currentTimeMillis() + ".jpg"));
        UCrop.Options options = new UCrop.Options();
        options.useSourceImageAspectRatio();
        UCrop.of(uri, destination)
                .withMaxResultSize(1080, 1080)
                .withOptions(options)
                .start(this);
    }

    private void onCropCallback(Intent data) {
        Uri uri = UCrop.getOutput(data);
        LogUtils.i(TAG, "onCropCallback uri: " + uri);
        if (uri != null) {
            onResult(uri.toString());
        }
    }

    public void onTakePicture(View v) {
        if (getImageType() == 0) {
            ToastUtils.getInstance().show(R.string.msg_image_type_empty);
            return;
        }
        cameraView.capture(this);
    }

    public void onOpenPicture(View v) {
        if (getImageType() == 0) {
            ToastUtils.getInstance().show(R.string.msg_image_type_empty);
            return;
        }
        if (Utils.checkRequestPermission(this, REQUEST_CODE, Manifest.permission.READ_EXTERNAL_STORAGE)) {
            return;
        }
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, OPEN_PICTURE);
    }

    public void onClose(View view) {
        finish();
    }

    private void getLatestPhoto() {
        if (isLatestPhoto) return;
        Uri latestPhoto = Utils.getLatestPhoto(this);
        if (latestPhoto != null) {
            isLatestPhoto = true;
            showPhoto(latestPhoto);
        }
    }

    private void showPhoto(Uri uri) {
        int radius = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics()) + 0.5f);
        RequestOptions options = new RequestOptions()
                .transform(new CenterCrop(), new RoundedCorners(radius));
        Glide.with(this)
                .load(uri)
                .apply(options)
                .into(ivPicture);
    }

    private void onResult(String uri) {
        Intent data = new Intent();
        data.putExtra(EXTRA_URI, uri);
        data.putExtra(EXTRA_IMAGE_TYPE, getImageType());
        setResult(RESULT_OK, data);
        finish();
    }
}
